/*
**    Copyright (C) 2003-2011 Institute for Systems Biology
**                            Seattle, Washington, USA.
**
**    This library is free software; you can redistribute it and/or
**    modify it under the terms of the GNU Lesser General Public
**    License as published by the Free Software Foundation; either
**    version 3 of the License, or (at your option) any later version.
**
**    This library is distributed in the hope that it will be useful,
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
**    Lesser General Public License for more details.
**
**    You should have received a copy of the GNU Lesser General Public
**    License along with this library; if not, write to the Free Software
**    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*/

package org.systemsbiology.iteration;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

import org.systemsbiology.util.Pair;

//TODO: unit test!
public class AllPairs<T> implements Iterable<Pair<T, T>>{
		List<? extends T> data;
		
		public AllPairs(List<? extends T> list){
			data = list;
		}
		
		public AllPairs(Collection<? extends T> collection){
			data = new ArrayList<T>(collection);
		}
		@Override
		public Iterator<Pair<T, T>> iterator() {
			return new BackingIterator(); //uses the data already in this object.
			//Allows multiple independent AllPairs iterations to run concurrently
		}
		
		private class BackingIterator implements Iterator<Pair<T, T>>{

			ListIterator<? extends T> one, two;
			Pair<T, T> preloaded;

			public BackingIterator(){
				one = data.listIterator();
				two = null;
				preloaded = null;
				lookahead();
			}
			
			private void lookahead(){
				if(two != null && two.hasNext()){
					Pair<T, T> p = new Pair<T,T>(preloaded.first, two.next());
					preloaded = p;
					return;
				}
				//two has no next
				if(one.hasNext()){
					Pair<T,T> p = new Pair<T,T>();
					p.first = one.next();
					two = data.listIterator(one.nextIndex());
					if(two.hasNext()){
						p.second = two.next();
						preloaded = p;
						return;
					} //two still has no next, so there wasn't anything in its list segment
					preloaded = null;
					return;
				}
				//out of list (we never had any list in the first place, in fact)
				preloaded = null;
				return;
			}
			
			@Override
			public boolean hasNext() {
				return(preloaded != null);
			}

			@Override
			public Pair<T, T> next() {
				Pair<T, T> ret = preloaded;
				lookahead();
				return ret;
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException("AllPairs.iterator does not support remove")
;			}
			
		}
	}
